import axios, {
  AxiosInstance,
  AxiosResponse,
  InternalAxiosRequestConfig,
  AxiosRequestConfig,
  Method,
} from "axios";
import {
  HTTP_HEADERS_CONTENT_TYPE,
  HTTP_STATUS_CODE_MAPPING,
} from "./http.config";
import { showToast } from "vant";
import { encryptUtils } from "@/utils";
import { AnyObject } from "@/types";
import { storage } from "@/core/storage";

const http = axios.create({
  // baseURL: import.meta.env.VITE_BASE_URL,
  baseURL: import.meta.env.PROD ? import.meta.env.VITE_BASE_URL : "",
  headers: HTTP_HEADERS_CONTENT_TYPE.JSON.headers,
  withCredentials: true, // 跨域请求时是否需要使用凭证
  timeout: 30000, // 请求超时时间
});

// 错误处理函数
function errorHandle(response: AxiosResponse) {
  const { status } = response;
  if (!status) return;
  const msg: string = HTTP_STATUS_CODE_MAPPING[status];
  switch (status) {
    case 400:
      // 处理错误信息，例如抛出错误信息提示，或者跳转页面等处理方式。
      // return Promise.resolve(error)
      break;
    case 401:
      //
      storage.clear();
      // 跳转登录逻辑
      break;
    case 404:
      break;
    default:
      break;
  }
  showToast(msg);
  return response;
}

/** 格式化http响应数据，兼容老接口和新接口 */
function formatResponseData(params: {
  code: number;
  data?: AnyObject | string;
  result?: AnyObject | string;
  msg?: string;
  [keyName: string]: any;
}) {
  const { code, msg, message, result, data } = params;
  const responseParams = { ...params };
  const filterKeys = ["code", "msg", "data", "result", "message"];
  filterKeys.forEach((key) => {
    Reflect.deleteProperty(responseParams, key);
  });
  let isStringResponse = false,
    responseData: any = data || result;
  if (responseData) {
    if (typeof responseData === "string") {
      isStringResponse = true;
    }
    if (responseData instanceof Array) {
      isStringResponse = true;
    }
  }
  return {
    code,
    msg: msg || message || "",
    data: isStringResponse
      ? responseData
      : { ...responseData, ...responseParams },
  };
}

// 成功处理函数
function successHandle(response: AxiosResponse) {
  let {
    status,
    data,
    config: { method, headers, url },
  } = response;
  if (
    method &&
    method.toLocaleUpperCase() === "POST" &&
    headers["Content-Type"] !==
      HTTP_HEADERS_CONTENT_TYPE.UPLOAD.headers["Content-Type"]
  ) {
    data = encryptUtils.decryptHandler(data, method);
  }
  printHttpRes("响应", url || "", data);
  data = formatResponseData(data);
  switch (status) {
    case 200:
      //
      const { code, msg } = data;
      if (code !== 200) showToast(msg || "系统错误，请稍后重试");
      return data;
    // ....
    default:
      return;
  }
}

function printHttpRes(type: string, url: string, params: AnyObject) {
  if (import.meta.env.MODE !== "prod") {
    console.log(type, url, params);
  }
}
// 请求拦截器
http.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    let { method, params, data, url } = config;
    method = (method || "GET").toLocaleUpperCase();
    if (
      config.headers["Content-Type"] ===
        HTTP_HEADERS_CONTENT_TYPE.UPLOAD.headers["Content-Type"] &&
      method === "POST"
    ) {
      return config;
    }
    const requestParams: AnyObject =
      method?.toLocaleUpperCase() === "GET" ? params : data || {};
    printHttpRes;
    //  这里要做加解密
    const encryptData = encryptUtils.encryptHandler(requestParams, method);
    printHttpRes("请求", url || "", requestParams);
    const headers = encryptUtils.getHeaders(encryptData, requestParams, method);
    Object.keys(headers).forEach((header: string) => {
      config.headers[header] = headers[header];
    });
    // 加密参数
    if (method === "POST") {
      config.data = encryptData;
    }
    return config;
  },
  (error) => {
    // 错误抛到业务代码
    return Promise.resolve(error);
  },
);

http.interceptors.response.use(
  (response: AxiosResponse) => {
    return successHandle(response);
  },
  (err) => {
    const errResponse = errorHandle(err.response);
    return Promise.reject(errResponse);
  },
);

class HttpService {
  private httpInstance: AxiosInstance;
  constructor(httpInstance: AxiosInstance) {
    this.httpInstance = httpInstance;
  }
  get<T>(
    url: string,
    params: Record<string, any> = {},
    config: Partial<AxiosRequestConfig> = {},
  ): Promise<T> {
    return this.httpInstance({
      method: "GET",
      url,
      params,
      ...config,
    });
  }
  post<T>(
    url: string,
    params: Record<string, any> = {},
    config: Partial<AxiosRequestConfig> = {},
  ): Promise<T> {
    return this.httpInstance({
      method: "POST",
      url,
      data: params,
      ...config,
    });
  }
}

export default new HttpService(http);
